#include "Task.hpp"
#include <iostream>
#include <string>
#include <vector>

#include <cstdlib>
#include <ctime>

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

const int processnum = 5;
const int exitcode = -1;
std::vector<task_func> tasks;

struct channel
{
    channel(int cmdfd, pid_t slaver_id, const std::string& processname)
        : _cmdfd(cmdfd)
        , _slaver_id(slaver_id)
        , _processname(processname)
    {}

    int _cmdfd;              //发送任务的文件描述符
    pid_t _slaver_id;        //子进程的PID
    std::string _processname;//子进程的名称
};

void Slaver()
{
    while (true)
    {
        int cmdcode = 0;
        int n = read(0, &cmdcode, sizeof(int));
        if (n == sizeof(int))
        {
            std::cout << "slaver: " << "pid: " << getpid() << " : cmdcode: " << cmdcode << std::endl;
            if (cmdcode >= 0 && cmdcode < tasks.size())
                tasks[cmdcode]();
            else if (cmdcode == exitcode)
                Task_Exit();
            else
                continue;
        }
        else if (n == 0)
            break;
        else
            continue;
    }
}

void InitProcessPool(std::vector<channel>* channels)
{
    std::vector<int> oldfds;
    for (int i = 0; i < processnum; ++i)
    {
        int pipefd[2] = { 0 };
        int n = pipe(pipefd);
        if (n < 0)
            exit(1);
        oldfds.push_back(pipefd[1]);

        pid_t id = fork();
        if (id == 0)
        {
            //close(pipefd[1]);
            for (int i = 0; i < oldfds.size(); ++i)
                close(oldfds[i]);
            
            dup2(pipefd[0], 0);
            close(pipefd[0]);

            Slaver();
            exit(0);
        }
        close(pipefd[0]);
        std::string name = "process" + std::to_string(i);
        channels->push_back(channel(pipefd[1], id, name));
    }

}

void ControlSlaver(const std::vector<channel>& channels)
{
    for (int processindex = 0, i = 0; true; processindex = (processindex + 1) % channels.size(), ++i)
    {
        int cmdcode = rand() % tasks.size();
        //int processindex = rand() % channels->size();
        std::cout << "parent sent" << i << ": " << cmdcode << " slaver id: " << channels[processindex]._slaver_id << " slaver name: " << channels[processindex]._processname << std::endl;
        write(channels[processindex]._cmdfd, &cmdcode, sizeof(cmdcode));
        sleep(1);
        if (i == 20)
        {
            std::cout << "parnet will exit" << std::endl;
            break;
        }
    }
}

void WaitChild(pid_t id)
{
    int state = 0;
    int rid = waitpid(id, &state, 0);
    if (rid == id)
    {
        std::cout << "Slaver Exit id: " << rid << " exit code:" << WEXITSTATUS(state) << std::endl;
        if (!WIFEXITED(state))
            std::cout << "sign code: " << (state & 0x7F) << std::endl;
    }
    else
        exit(2);
}

void SlaverALLExit(const std::vector<channel>& channels)
{
    for (int i = 0; i < channels.size(); ++i)
        write(channels[i]._cmdfd, &exitcode, sizeof(int));
    sleep(3);
    for (int i = 0; i < channels.size(); ++i)
        WaitChild(channels[i]._slaver_id);
    std::cout << "Slaver all exit" << std::endl;
}

void QiutProcess(const std::vector<channel>& channels)
{
    //回收方式1
    for (int i = channels.size() - 1; i >= 0; --i)
    {
        close(channels[i]._cmdfd);
        WaitChild(channels[i]._slaver_id);
    }
    std::cout << "Slaver all exit" << std::endl;
}

//parent w  child r
int main()
{
    srand((unsigned int)time(NULL) ^ getpid());
    LoadProcess(&tasks);

    std::vector<channel> channels;
    InitProcessPool(&channels);
    
    ControlSlaver(channels);

    SlaverALLExit(channels);

    return 0;
}